/////////////////////////////////////////////////////////////////////
//
//  MOE Framework (Meta Object Encapsulation Framework)
//
//  Original Author: Wiksy Wang, 2011
//
/////////////////////////////////////////////////////////////////////

#ifndef MOE_NAME_NAME_PATH_H
#define MOE_NAME_NAME_PATH_H

#include <boost/noncopyable.hpp>
#include <boost/static_assert.hpp>

#include "../RawByteVector.h"
#include "../RawByteVectorRef.h"

namespace MOE
{

namespace Name
{

// Stores the in-place information about a name path using RawByteVector.
class NamePath : boost::noncopyable
{
public:
	static const NamePath gEmptyPath;

public:
	NamePath();

	template <class CharType>
	explicit NamePath(const CharType* const str, const CharType delimiter = CharType('.'))
		: _path(str)
		, _delimiter(delimiter)
		, _charSize(sizeof(CharType))
		, _splitCount(0)
		, _splitIndices(0)
	{
		BOOST_STATIC_ASSERT(sizeof(CharType) <= sizeof(unsigned int));
		InitPath(static_cast<unsigned int>(delimiter));
	}

	template <class CharContainerType>
	explicit NamePath(const CharContainerType& str, const typename CharContainerType::value_type delimiter = typename CharContainerType::value_type('.'))
		: _path(str)
		, _delimiter(delimiter)
		, _charSize(sizeof(typename CharContainerType::value_type))
		, _splitCount(0)
		, _splitIndices(0)
	{
		BOOST_STATIC_ASSERT(sizeof(typename CharContainerType::value_type) <= sizeof(unsigned int));
		InitPath(static_cast<unsigned int>(delimiter));
	}

	// Although RawByteVector can fit in the template parameter of CharContainerType, the size of value_type (char)
	// does not reflect the real character size. Thus, when we want to initialize a NamePath with RawByteVector,
	// we should be using this function instead.
	NamePath(const RawByteVector& str, const size_t charSize, const unsigned int delimiter = '.');

	~NamePath();

	const RawByteVector& GetPath() const { return _path; }
	size_t GetSplitCount() const { return _splitCount; }

	unsigned int GetDelimiter() const { return _delimiter; }
	size_t GetCharSize() const { return _charSize; }

	// Gets the sub path starting from the index-th split.
	RawByteVectorRef GetSubPath(size_t index) const;

	// Gets the path segment from startIndex to endIndex (inclusive).
	RawByteVectorRef GetSegment(size_t startIndex, size_t endIndex) const;

	RawByteVectorRef GetFirstSegment() const { return GetSegment(0, 0); }
	RawByteVectorRef GetLastSegment() const { return GetSubPath(GetSplitCount()); }

private:
	void InitPath(const unsigned int delimiter);

	size_t GetPartStartCharIndex(size_t index) const;
	size_t GetPartEndCharIndex(size_t index) const;

	RawByteVector _path;
	unsigned int _delimiter;
	size_t _charSize;
	size_t _splitCount;
	size_t* _splitIndices;

	friend class NamePathRef;
};

}

}

#endif
